package eu.smoothit.sis.admin.backendBean;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
import javax.faces.event.ValueChangeEvent;

import eu.smoothit.sis.db.SisDAOFactory;
import eu.smoothit.sis.db.api.daos.IComponentConfigDAO;
import eu.smoothit.sis.db.impl.entities.ComponentConfigEntry;

public abstract class ComponentConfigAbstract {
	// Constants
	// ----------------------------------------------------------------------------------

	public static final String METERING_PROP_BGP_FILE_NAME = "Metering-BGP-File-Name";
	public static final String METERING_PROP_LOCAL_FILE_NAME = "Metering-BGP-Local-File-Name";
	public static final String METERING_PROP_REMOTE_IP_INFO_SRC = "Metering-Remote-IP-Info-Src";
	public static final String METERING_PROP_LOCAL_IP_INFO_SRC = "Metering-Local-IP-Info-Src";
	// Properties
	// ---------------------------------------------------------------------------------
	private List<ComponentConfigEntry> dataList;

	// define DAO
	protected IComponentConfigDAO dataDAO = (IComponentConfigDAO) SisDAOFactory
			.getFactory().createComponentConfigDAO();
	// used by get instance of current FacesContext
	private static FacesContext fc;

	// Form actions
	// -------------------------------------------------------------------------------
	public void actionLoad() {
		try {
			dataList = dataDAO.getAll();
		} catch (Exception e) {
			setErrorMessage(e.getMessage() + " Cause: " + e.getCause());
			e.printStackTrace();
		}
	}

	/**
	 * query entry of table config_props_config_entry
	 * 
	 * @return ONLY the first one matched
	 */
	public String searchComponentConfigEntry(String componentName,
			String propName) {
		String value = null;
		try {
			dataList = dataDAO.getAll();
		} catch (Exception e) {
			setErrorMessage(e.getMessage() + " Cause: " + e.getCause());
			e.printStackTrace();
		}
		for (ComponentConfigEntry ConfigEntry : dataList) {
			if ((ConfigEntry.getComponent().equals(componentName))
					&& (ConfigEntry.getPropName().equals(propName))) {
				value = ConfigEntry.getValue().toString();
				return value;
			}
		}
		return value;
	}

	/**
	 * create/update ComponentConfig entities if
	 * 
	 * @param componentName
	 * @param propName
	 * @param value
	 *            : if empty string, delete, return 0
	 * @return 0:delete, 1: new added;2: updated 3: error, find more than one 4:
	 *         no changed entry
	 */
	public int saveComponentConfigEntry(String componentName, String propName,
			String value) {
		ComponentConfigEntry ConfigEntry = new ComponentConfigEntry();
		ConfigEntry.setComponent(componentName);
		ConfigEntry.setPropName(propName);
		try {
			// ConfigEntry = dataDAO.findByComponentAndName(componentName,
			// propName);
			List<ComponentConfigEntry> foundConfiEntries = dataDAO
					.get(ConfigEntry);
			// found more than one entry, duplicate
			if (foundConfiEntries.size() > 1) {
				setErrorMessage("find more than one entry for component|property:"
						+ componentName + "|" + propName);

			} else if (foundConfiEntries.size() == 1) {
				ConfigEntry = foundConfiEntries.get(0);
				// remove if value is empty
				if (value.length() == 0) {
					dataDAO.remove(ConfigEntry);
					return 0;
					// no change if value not modified
				} else if (ConfigEntry.getValue().toString().equals(value)) {
					return 4;
				}
				// update existing one if value modified
				else {
					ConfigEntry.setValue(value);
					dataDAO.update(ConfigEntry);
					return 2;
				}
				// create new entry if value not empty
			} else if (foundConfiEntries.size() == 0 && value.length() != 0) {
				ConfigEntry = new ComponentConfigEntry(componentName, propName,
						value);
				dataDAO.persist(ConfigEntry);
				return 1;
			}

		} catch (Exception e) {
			setErrorMessage(e.getMessage() + " Cause: " + e.getCause());
			e.printStackTrace();
		}
		return 3;
	}

	/**
	 * after detecting value pair change, enable SAVE
	 * 
	 * @param valuePair
	 * @param propName
	 * @param enableTag
	 * @param event
	 *            TODO return false when detect value reset, a list of boolean
	 *            for final judge
	 * @return
	 */
	public boolean valueChangeCache(Map<String, String> storedValuePair,
			Map<String, String> cachedValuePair, String propName,
			ValueChangeEvent event) {
		String newAssignedValue = (String) event.getNewValue();
		String oldValue = (String) event.getOldValue();
		if (newAssignedValue != null && newAssignedValue.length() > 0) {
			// a new value assigned
			if (!newAssignedValue.equals(oldValue)) {
				// if the property already in cache
				// TODO add fixed component name iop
				if (storedValuePair.containsKey(propName)) {
					// compare new assgined value to cached value
					if (storedValuePair.get(propName).equals(newAssignedValue)) {
						// remove the property if the same, which mean value
						// changed back
						cachedValuePair.remove(propName);
					} else
						cachedValuePair.put(propName, newAssignedValue);
				}
				// a first time to save
				else {
					// if there is change
					if (!cachedValuePair.get(propName).equals(newAssignedValue)) {
						cachedValuePair.remove(propName);
						cachedValuePair.put(propName, newAssignedValue);
					}

				}

			}
		}
		System.err.println("bob:" + cachedValuePair.size());
		if (cachedValuePair.isEmpty()) {
			// disable save buttong
			return false;
		} else {
			return true;
		}
	}

	// used for store parameters
	// protected Map<String, String> valuePairs = new HashMap<String, String>();

	// Helpers
	// ------------------------------------------------------------------------------------

	/**
	 * Set global error message.
	 * 
	 * @param errorMessage
	 */
	protected static void setErrorMessage(String errorMessage) {
		resetErrorMessage();
		// log(errorMessage);
		fc = FacesContext.getCurrentInstance();
		fc.addMessage(null, new FacesMessage(errorMessage));
	}

	protected static void resetErrorMessage() {
		// remove existing message
		fc = FacesContext.getCurrentInstance();
		Iterator<FacesMessage> iterator = fc.getMessages();
		while (iterator.hasNext()) {
			FacesMessage fm = (FacesMessage) iterator.next();
			fm.setDetail("");
			fm.setSummary("");
		}
	}

	/**
	 * update values of UI components
	 */
	public void refreshPage() {
		FacesContext context = FacesContext.getCurrentInstance();
		String viewId = context.getViewRoot().getViewId();
		ViewHandler handler = context.getApplication().getViewHandler();
		UIViewRoot root = handler.createView(context, viewId);
		root.setViewId(viewId);
		context.setViewRoot(root);
	}

	/**
	 * advance submit progress
	 */
	public void advanceSubmit(ValueChangeEvent event) {
		if (!event.getPhaseId().equals(PhaseId.INVOKE_APPLICATION)) {
			event.setPhaseId(PhaseId.INVOKE_APPLICATION);
			event.queue();
			return;
		}
	}

}
